package com.ruoyi.syncCore;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.kingdee.bos.webapi.sdk.K3CloudApi;
import com.ruoyi.common.core.domain.KingdeeBillRequestBody;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.interfaceConfig.businessObject.domain.BusinessFieldSetting;
import com.ruoyi.interfaceConfig.businessObject.domain.vo.BusinessObjectConfigVo;
import com.ruoyi.interfaceConfig.businessObject.domain.vo.FieldSettingVo;
import com.ruoyi.interfaceConfig.businessObject.service.IBusinessFieldSettingService;
import com.ruoyi.interfaceConfig.businessObject.service.IBusinessObjectConfigService;
import com.ruoyi.interfaceConfig.sceneConfig.domain.vo.SceneConfigVo;
import com.ruoyi.interfaceConfig.sceneConfig.service.ISceneConfigService;
import com.ruoyi.syncCore.domain.SyncSuccessLog;
import com.ruoyi.syncCore.mapper.SyncSuccessLogMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Future;

/**
 * @author Yuan
 * @description
 * @date 2024/3/16
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class SyncCoreTemplate {

    private final ISceneConfigService sceneConfigService;
    private final IBusinessObjectConfigService businessObjectConfigService;
    private final IBusinessFieldSettingService businessFieldSettingService;
    private final SyncSuccessLogMapper syncSuccessLogMapper;
    private final K3CloudApi client;
    private final JdbcTemplate jdbcTemplate;
    private final ThreadPoolTaskExecutor threadPoolTaskExecutor;

    //数据往本系统同步
    public void syncDown(SceneConfigVo sceneConfigVo) {
        try (Connection connection = jdbcTemplate.getDataSource().getConnection()) {
            connection.setAutoCommit(false);
            //根据对象1 ID查询金蝶中的数据
            Long sysObjId1 = sceneConfigVo.getSysObjId1();
            Long sysObjId2 = sceneConfigVo.getSysObjId2();
            Long sceneId = sceneConfigVo.getId();
            //金蝶对象的字段信息
            FieldSettingVo fieldSettingVo = businessFieldSettingService.selectFieldById(sceneId, sysObjId1, sysObjId2);
            //序列号追溯系统的字段信息
            List<String> sysObj2Field = businessFieldSettingService.selectFieldListById(sceneId, sysObjId2);
            KingdeeBillRequestBody kingdeeBillRequestBody = new KingdeeBillRequestBody();
            kingdeeBillRequestBody.setFormId(fieldSettingVo.getSyncerFormId());
            kingdeeBillRequestBody.setFieldKeys(fieldSettingVo.getSyncerFieldStr());
            String lastUpdateDate = syncSuccessLogMapper.selectLastRecordDate(sceneId);
            if(StringUtils.isEmpty(lastUpdateDate)) {
                lastUpdateDate = "1967-01-01 00:00:00";
            }
            //查询系统2的主键(避免错误Too may data xxx)
            List<String> primaryKeys = businessFieldSettingService.selectPrimaryKeysById(sysObjId2);
            if(primaryKeys == null) {
                throw new ServiceException("同步失败");
            }
            String primaryKey = primaryKeys.get(0);
            //1、根据上次更新时间获取最新的更新记录，然后更新本地记录
            BusinessObjectConfigVo businessObjectConfigVo = businessObjectConfigService.selectBusinessObjectConfigById(sceneConfigVo.getSysObjId2());
            String tableName = businessObjectConfigVo.getBusinessObjectFlag();
            //使用JDBCTemplate获取执行结果String
            //判断有更新标识
            if("01".equals(businessObjectConfigVo.getHasUpdateFlag())) {
                JSONObject filterCondition1 = new JSONObject();
                filterCondition1.put("FieldName", "FModifyDate");
                filterCondition1.put("Compare", "39");
                filterCondition1.put("Value", lastUpdateDate);
                filterCondition1.put("Left", "");
                filterCondition1.put("Right", "");
                filterCondition1.put("Logic", "0");

                kingdeeBillRequestBody.setFilterString(new JSONObject[]{filterCondition1});
                // 将对象转为JSON字符串
                String jsonString = getJSON(kingdeeBillRequestBody);
                List<List<Object>> needUpdate = client.executeBillQuery(jsonString);


                String needUpdateData = String.valueOf(needUpdate);

                boolean getUpdateError = needUpdateData.contains("ErrorCode=500");
                if(getUpdateError) {
                    throw new ServiceException("同步失败");
                }
                //将同步的数据进行拆分
                int kk = needUpdate.size() / 1000 + (needUpdate.size() % 1000 > 0 ? 1 : 0);
                List<Future<Integer>> futureList = new ArrayList<>();
                //根据i，对needUpdate进行分批处理操作
                for (int j = 0; j < kk; j++) {
                    int finalJ = j;
                    Future<Integer> future = threadPoolTaskExecutor.submit(() -> {
                        //更新数据
                        return updateDataBatch(fieldSettingVo, sysObj2Field, primaryKey, tableName, needUpdate, finalJ);
                    });
                    futureList.add(future);
                }
                int count = 0;
                for (Future<Integer> future : futureList) {
                    try {
                        count += future.get();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    log.info("更新成功行数：{}",count);
                }
            }

            //2、获取日期以上次同步时间开始的记录,此部分数据用于新增
            JSONObject filterCondition2 = new JSONObject();
            filterCondition2.put("FieldName", "FCreateDate");
            filterCondition2.put("Compare", "39");
            filterCondition2.put("Value", lastUpdateDate);
            filterCondition2.put("Left", "");
            filterCondition2.put("Right", "");
            filterCondition2.put("Logic", "0");
            kingdeeBillRequestBody.setFilterString(new JSONObject[]{filterCondition2});
            String jsonData2 = JSON.toJSONString(kingdeeBillRequestBody);
            List<List<Object>> needInsert = client.executeBillQuery(jsonData2);
            //查询外键个数
            List<BusinessFieldSetting> listBf=businessFieldSettingService.selectisForeignKeyById(sysObjId1);
            //判断是否有外键
            if (listBf.size()!=0){
                String[] fields  = fieldSettingVo.getSyncerFieldStr().split(",");
                String[] split = fieldSettingVo.getReceiverFieldStr().split(",");
                Set<String> set1 = new HashSet<>(sysObj2Field);
                Set<String> set2 = new HashSet<>(Arrays.asList(split));
                StringBuilder valueOccur = new StringBuilder();
                set1.forEach(element -> {
                            if (!set2.contains(element)) {
                                valueOccur.append("," + element);
                            }});
                fieldSettingVo.setReceiverFieldStr(fieldSettingVo.getReceiverFieldStr()+valueOccur);
                            //记录字段在第几个
                for (int i = 0; i < needInsert.size(); i++) {
                    for (BusinessFieldSetting businessFieldSetting:listBf) {
                        // 遍历字段数组来找到目标字段的位置
                        int a = selectNumber(fields, businessFieldSetting.getJavaField());
                        FieldSettingVo fieldSettingVo01 = businessFieldSettingService.selectFieldByTableId(businessFieldSetting.getAssociationTable());
                        KingdeeBillRequestBody kingdeeBillRequestBody02 = new KingdeeBillRequestBody();
                        kingdeeBillRequestBody02.setFieldKeys(fieldSettingVo01.getSyncerFieldStr());
                        kingdeeBillRequestBody02.setFormId(fieldSettingVo01.getSyncerFormId());
                        JSONObject filterCondition1 = new JSONObject();
                        filterCondition1.put("FieldName", businessFieldSetting.getForeignName());
                        filterCondition1.put("Compare", "67");
                        filterCondition1.put("Left", "");
                        filterCondition1.put("Right", "");
                        filterCondition1.put("Logic", "0");
                        filterCondition1.put("Value", needInsert.get(i).get(a));
                        kingdeeBillRequestBody02.setFilterString(new JSONObject[]{filterCondition1});
                        String jsonData3 = JSON.toJSONString(kingdeeBillRequestBody02);
                        List<List<Object>> needInsert02 = client.executeBillQuery(jsonData3);
                        needInsert.get(i).addAll(needInsert02.get(0));
//                        //判断判断插入第几个
//                        String[] fields01  = fieldSettingVo01.getSyncerFieldStr().split(",");
//                        //将查到的数据加入到insert语句中
//                        for (int j = 0; j < fields01.length; j++) {
//                            needInsert.get(i).add(selectNumber(fields,fields01[j]),needInsert02.get(0).get(j));
//                        }
                    }
                }

            }

            String resultJson = String.valueOf(needInsert);
            boolean error = resultJson.contains("ErrorCode=500");
            if(error) {
                throw new ServiceException("同步失败");
            }

            //需要insert的数据
            if (needInsert != null && !needInsert.isEmpty()) {
                String receiverTableName = fieldSettingVo.getReceiverFormId();
                String columns = fieldSettingVo.getReceiverFieldStr();
                StringBuilder valueOccur = new StringBuilder();
                for (int i = 0; i < sysObj2Field.size(); i++) {
                    valueOccur.append("?,");
                }
                valueOccur.deleteCharAt(valueOccur.lastIndexOf(","));
                String sql = "INSERT INTO " + receiverTableName + " (" + columns + ") VALUES ("+valueOccur+")"; // 根据你的字段数量添加?

                int batchSize = needInsert.size();
                int[] insertCounts = jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
                    @Override
                    public void setValues(PreparedStatement ps, int i) throws SQLException {
                        //插入数据
                        insertDataBatch(ps, i, needInsert, sysObj2Field);
                    }

                    @Override
                    public int getBatchSize() {
                        return batchSize;
                    }
                });
            }

            //同步成功，记录同步时间
            String integrationDirection = sceneConfigVo.getIntegrationDirection();
            StringBuilder stringBuilder = new StringBuilder();
            if("02".equals(integrationDirection)) {
                //从左同步到右
                stringBuilder.append(sceneConfigVo.getSysObjName1()+"同步到"+sceneConfigVo.getSysObjName2());
            }else{
                stringBuilder.append(sceneConfigVo.getSysObjName2()+"同步到"+sceneConfigVo.getSysObjName1());
            }
            SyncSuccessLog syncSuccessLog = new SyncSuccessLog();
            syncSuccessLog.setTaskName(stringBuilder.toString());
            syncSuccessLog.setSceneId(sceneId);
            syncSuccessLogMapper.insertWithBean(syncSuccessLog);

            connection.commit();

        } catch (SQLException e) {
            // 处理异常
            throw new ServiceException("获取sql连接异常");
        } catch(Exception e) {
            throw new ServiceException("同步失败");
        }

    }
    private int selectNumber(String[] fields,String word){
        for (int i = 0; i < fields.length; i++) {
            // 使用trim()方法去除字段两侧的空格（如果有的话）
            if (fields[i].trim().equals(word)) {
                return i ;
            }
        }
        // 如果未找到，返回-1
        return -1;
    }

    private void insertDataBatch(PreparedStatement ps, int i, List<List<Object>> needInsert, List<String> sysObj2Field) throws SQLException {
        List<Object> row = needInsert.get(i);
        List<List<String>> list =businessFieldSettingService.selectFieldByColumnName(sysObj2Field);
        for (int j = 0; j < row.size(); j++) {
            Object value = row.get(j);
            if (sysObj2Field.contains("status") && j == sysObj2Field.indexOf("status")) {
                if ("A".equals(value)) {
                    ps.setInt(j + 1, 0);
                } else {
                    ps.setInt(j + 1, 2);
                }
            } else if ("C".equals(value)) {
                if ("C".equals(value)) {
                    ps.setInt(j + 1, 0);
                } else {
                    ps.setInt(j + 1, 2);
                }
            } else if (list.get(j).get(0).equals("String")||list.get(j).get(0).equals("Date")) {
                ps.setString(j + 1, value + "");
            } else if (list.get(j).get(0).equals("Integer")) {
                if (value instanceof Double) {
                    Double doubleValue = (Double) value;
                    if (doubleValue.equals(Math.floor(doubleValue)) && doubleValue.longValue() <= Integer.MAX_VALUE && doubleValue.longValue() >= Integer.MIN_VALUE) {
                        // 转换为 long，然后转换为 Integer（虽然直接转换为 int 也可以，但这里为了清晰性）
                        int intValue = (int) doubleValue.longValue();
                        ps.setInt(j + 1, intValue);
                    } else {
                        ps.setInt(j + 1, (Integer) value);
                    }

//                if (value instanceof String) {
//                    ps.setString(j + 1, (String) value);
//                } else if (value instanceof Integer) {
//                    ps.setInt(j + 1, (Integer) value);
//                } // 根据实际数据类型添加更多的set方法
                } else if (list.get(j).get(0).equals("Long")) {
                    ps.setLong(j + 1, (Long) value);
//                ps.setLong(j + 1, (Long) value);
                }

            }
        }}

    private int updateDataBatch(FieldSettingVo fieldSettingVo, List<String> sysObj2Field, String primaryKey, String tableName, List<List<Object>> needUpdate, int finalJ) {
        int count = 0;
        // needUpdate有超过1000条，就拿1000，未满1000,就拿实际数量
        List<List<Object>> lists = needUpdate.subList(finalJ * 1000, Math.min((finalJ + 1) * 1000, needUpdate.size()));
        for (List<Object> objects : lists) {
            StringBuilder sb = new StringBuilder();
            if (fieldSettingVo.getReceiverFieldStr().contains("delFlag")) {
                sb.append("delFlag=0,");
            }
            for (int i = 1; i < sysObj2Field.size(); i++) {
                String columnName = sysObj2Field.get(i);
                Object o = objects.get(i);
                if ("status".equals(columnName)) {
                    sb.append(columnName + "='" + (o == "A" ? 0 : 2) + "',");
                } else {
                   sb.append(columnName + "='" + o + "',");
                }
            }
            sb.deleteCharAt(sb.lastIndexOf(","));
            //更新表信息=
            String updateLocalSql = "update " + tableName + " set " + sb.toString() + " where " + primaryKey + " = '" + objects.get(0) + "'";
            int row = jdbcTemplate.update(updateLocalSql);
            count += row;
        }
        return count;
    }

    private String getJSON(KingdeeBillRequestBody kingdeeBillRequestBody) {
        JSONObject jsonObject = new JSONObject();
        String formId = kingdeeBillRequestBody.getFormId();
        String fieldKeys = kingdeeBillRequestBody.getFieldKeys();
        JSONObject[] filterString = kingdeeBillRequestBody.getFilterString();
        String orderString = kingdeeBillRequestBody.getOrderString();
        int topRowCount = kingdeeBillRequestBody.getTopRowCount();
        int startRow = kingdeeBillRequestBody.getStartRow();
        int limit = kingdeeBillRequestBody.getLimit();
        String subSystemId = kingdeeBillRequestBody.getSubSystemId();

        jsonObject.put("FormId", StringUtils.isEmpty(formId) ? "": formId);
        jsonObject.put("FieldKeys", StringUtils.isEmpty(fieldKeys) ? "": fieldKeys);
        jsonObject.put("FilterString", filterString == null ? "": filterString);
        jsonObject.put("OrderString", orderString);
        jsonObject.put("TopRowCount", topRowCount);
        jsonObject.put("StartRow", startRow);
        jsonObject.put("Limit", limit);
        jsonObject.put("SubSystemId", subSystemId);
        return jsonObject.toJSONString();
    }

    public void syncDataForDown(Long sceneId) {
        SceneConfigVo sceneConfigVo = sceneConfigService.selectSceneConfigById(sceneId);
        if("02".equals(sceneConfigVo.getIntegrationDirection())) {
            //金蝶数据同步到本地
            syncDown(sceneConfigVo);
        }
    }
}
